/* Complet (Autocompletion through Graph Databases)
 *  Copyright (C) 2012  Paul Wagner, Till Speicher
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 3 of the License, or (at your
 *  option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, see <http:/* www.gnu.org/licenses/>.
*/

/*
 * Main Server
 *
 * @ author Paul Wagner
 */
package complet.app.svr;

import com.google.gson.Gson;
import complet.db.Retrieval;
import complet.helper.CompletData;
import complet.helper.ConfigHelper;
import complet.helper.IOHelper;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.HashMap;
import java.util.TreeMap;

public class CompletServer {

    private ServerSocket server;
    private Retrieval ret;
    private Gson jsonHandler;

    public CompletServer() {
        // Load and buffer database
        ret = new Retrieval();
        ret.setP1(ConfigHelper.P1);
        ret.setP2(ConfigHelper.P2);
        ret.setP3(ConfigHelper.P3);
        ret.setP4(ConfigHelper.P4);

        //JSON-Handler
        jsonHandler = new Gson();

        try {
            server = new ServerSocket(ConfigHelper.SRV_PORT);
        } catch (IOException e) {
            IOHelper.strongLog("(CompletServer.init()) Error while initialize server: " + e.getMessage());
        }
        IOHelper.strongLog("(CompletServer.init()) Server startup completed...");
    }

    public static void main(String[] args) {
        // Load config file
        ConfigHelper.DB_PATH = "E:\\paul\\Dokumente\\MyDocuments\\NetBeans Workspace\\Completion\\dbs\\db_ngrams_ucsc_r5.db";
        ConfigHelper.BUFFER = false;

        if (args.length > 0) {
            ConfigHelper.loadConfigFile(args[0]);
        }

        // Make Server
        CompletServer server = new CompletServer();
        server.handleConnection();
    }

    public void handleConnection() {
        IOHelper.strongLog("(CompletServer.handleConnection()) Wait for client connection...");

        //
        // The server does a loop here to accept all connection initiated by the
        // client application.
        //
        while (true) {
            try {
                Socket socket = server.accept();
                new ConnectionHandler(socket, ret, jsonHandler);
            } catch (IOException e) {
                IOHelper.strongLog("(CompletServer.handleConnection()) Error while waiting for connection: " + e.getMessage());
            }
        }
    }
}

class ConnectionHandler implements Runnable {

    private Socket socket;
    private Retrieval ret;
    private Gson jsonHandler;

    public ConnectionHandler(Socket socket, Retrieval ret, Gson jsonHandler) {
        this.socket = socket;
        this.ret = ret;
        this.jsonHandler = jsonHandler;

        Thread t = new Thread(this);
        t.start();
    }

    public void run() {
        try {
            //
            // Read input words
            //
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            String input = (String) ois.readObject();
            CompletData data = jsonHandler.fromJson(input, CompletData.class);
            //IOHelper.log("(CompletServer.thread.run()) Recieved new sentence: " + data.toSentence());

            //
            // Do DB Maintanence
            //
//            if(data.words.length == 4 && ConfigHelper.APPEND_NEW_DATA){
//                if(data.offset.length() == 1){
//                    ret.appendSentence(data.words, data.uid);
//                }
//            }

            //
            // Make retrieval
            //
            ret.setSentence(data.words, data.offset);
            int set;
            double time;
            if(data.primitive){
                time = ret.primitiveEval();
                data.primitive = true;
                set = 3;
            }else{
                if(data.words.length == 0 && data.use_primitive){
                    time = ret.primitiveEval();
                    data.primitive = true;
                    set = 3;
                }else{
                    set = 1;
                    time = ret.eval(); 
                    if(ret.getSortedKeySet(set).isEmpty() && data.use_primitive){
                        set = 3;
                        data.primitive = true;
                        time = time + ret.primitiveEval();
                    }
                }
            }
            IOHelper.log(data.uid + "\t" + data.toSentence() + "\t" + set + "\t" + time);


            //
            // Send result back to client
            //
            TreeMap<Integer, String> map = new TreeMap<Integer, String>();
            int c = 0;
            for (String key : ret.getSortedKeySet(set)) {
                if (c >= 10) {
                    break;
                }
                //map.put(key, ret.getResult().get(key).getAVG_RELLOC());  // Sortierungsprobleme
                map.put(c, key);  // Damit behoben, aber das gibt dem Client dann keine genauere Bewertung. Können wir im Moment aber eh nicht gebrauchen
                c++;
            }
            CompletData result = new CompletData(map, data.primitive);

            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(jsonHandler.toJson(result));

            ois.close();
            oos.close();
            socket.close();

            IOHelper.strongLog("(CompletServer.handleConnection()) Wait for client connection...");
        } catch (Exception e) {
            IOHelper.strongLog("(CompletServer.thread.run()) Error while handling connection: " + e.getMessage());
        }
    }
}
